package br.academia.arq.dao;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.tool.hbm2ddl.SchemaExport;

import br.academia.arq.erros.DAOException;

/**
 * Fábrica de Daos
 */
public class DAOFactory {
	//public static Logger logger = Logger.getLogger(DAOFactory.class); 
	
	/**
	 * Padrão de projeto singleton
	 */
	protected static DAOFactory singleton = null;
	
	/** 
	 * SessionFactory do EducProject
	 */
	protected SessionFactory sessionFactory;
	
	protected DAOFactory(){
		
	}
	
	/**
	 * Cria as tabelas no banco de dados
	 * @param classe
	 * @throws DAOException
	 */
	public synchronized static void criarTabela(@SuppressWarnings("rawtypes") Class[] classe) throws DAOException{
		
		try{
			AnnotationConfiguration cfg = new AnnotationConfiguration();
			
			escolherLocal(cfg);
			
			for(@SuppressWarnings("rawtypes") Class c : classe)
				cfg.addAnnotatedClass(c);
			
			new SchemaExport(cfg).create(true, true);
		}catch (Exception e) {
			throw new DAOException(e);
		}
	}

	/**
	 * Configura um AnnotationConfiguration de acordo com a constante escolhida na variavel local
	 * Serve para oferecer uma rápida troca do banco, entre o de produção e o de testes.
	 * @param cfg
	 */
	private static void escolherLocal(AnnotationConfiguration cfg) {
		cfg.configure("br/academia/arq/dao/local.cfg.xml");
	}
	
	/**
	 * Cria a session factory de acordo com o local escolhido
	 */
	private void criarSessionFactory(){
		AnnotationConfiguration cfg = new AnnotationConfiguration();
		
		escolherLocal(cfg);
		
		sessionFactory = cfg.buildSessionFactory();
	}
	
	/**
	 * Retorna a única instância desta classe. Note que o synchronized torna este método em média 100 vezes mais lento.
	 * @return única instância desta classe.
	 */
	public static DAOFactory getInstance() {
		if (singleton == null)
			singleton = new DAOFactory();
		return singleton;
	}
	
	/**
	 * Retorna o SessionFactory
	 * @see Remover o synchronized e tornar estático
	 * @return SessionFactory do IProject
	 */
	public synchronized SessionFactory sessionFactory() {
		if (sessionFactory == null)
			criarSessionFactory();
		return sessionFactory;
	}
	
	/**
	 * Retorna a instância do DAO
	 * @param daoClass Herda de GenericDAO
	 * @return A instância do DAO
	 * @throws DAOException
	 */
	public <T extends GenericDAO> T getDAO(Class<T> daoClass)throws DAOException {

		try {
			T dao = daoClass.newInstance();
			return dao;

		} catch (Exception e) {
			throw new DAOException("Erro ao obter DAO " + e.getMessage(), e);
		}

	}
	
	
	
	/**
	 * Fecha o SessionFactory e o disponibiliza para o GB
	 */
	public void clean(){
		if(sessionFactory != null){			
			sessionFactory.close();
			sessionFactory = null;
		}
	}
	
	/**
	 * Fecha o SessionFactory
	 */
	@Override
	protected void finalize() {
		if(sessionFactory != null)
			sessionFactory.close();
	}
	
}
